/*
 * Description: 事件日志相关事件处理
 */
#ifndef LOG_EVENT_HANDLER_H
#define LOG_EVENT_HANDLER_H

#include <ctime>
#include <chrono>
#include <mutex>
#include "stability_common.h"
#include "singleton.h"

namespace DFX {
// 注册表的位置
const HKEY HROOT = HKEY_CURRENT_USER;
const LPCTSTR SUBK_EY = TEXT("Software\\VmAgentService\\dfx");
const LPCSTR ITEM_KEY = "LogEventLastCheckTime";

class LogEventHandler {
public:
    LogEventHandler() = default;
    void ReportOldEvents();
    ~LogEventHandler();
    bool Init();
    void DeInit();
    void SubscribeEvents();
    void UnsubscribeEvents();

private:
    string FormatTime(const chrono::system_clock::time_point &tp);
    wstring GetEventQuery(string startTimeStr);
    DWORD ProcessEventDatas(EVT_HANDLE eventHandle);
    void ProcessXmlEvent(PEVT_VARIANT eventSystemHeader, LPWSTR xmlBufferData);
    wstring RemoveXmlns(LPWSTR xml);
    static DWORD WINAPI EVTCallback(EVT_SUBSCRIBE_NOTIFY_ACTION action, PVOID userContext, EVT_HANDLE event);
    VOID DoProcessEvent(EVT_HANDLE event);
    void UpdateCheckTimeStr();

    mutex processEventMutex;

    string lastCheckTimeStr = "";
    EVT_HANDLE sysContext = nullptr;
    EVT_HANDLE subscriptionAppEvt = nullptr;
    EVT_HANDLE subscriptionSysEvt = nullptr;
    LPWSTR renderBuffHeader = nullptr; // 单个事件头buffer
    LPWSTR renderBuffData = nullptr;   // 单个事件内容buffer

    /* 事件 ID 41：系统未正常关闭（蓝屏崩溃或硬件故障）
        1000: app error
        1001: windows error Reporting
        1002: app hang
    */
    static const UINT16 EVENTID_SHUTDOWN_UNEXPECTED = 6008;
    static const UINT16 EVENTID_SHUTDOWN_KERNEL_POWER = 41;
    static const UINT16 EVENTID_APPLICATION_HANG = 1002;
    static const UINT16 EVENTID_APPLICATION_ERROR = 1000;
    static const UINT16 EVENTID_WINDOWS_ERROR_REPORTING = 1001;
    static const UINT16 EVENTID_MEM_NOTENOUGH = 2004;

    // (EventId,ProviderName) -> ( EventName,Properties)
    const map<pair<UINT16, string>, pair<string, vector<pair<string, string>>>> EVENT_XML_CONFIGS = {
        { make_pair(EVENTID_SHUTDOWN_KERNEL_POWER, "Microsoft-Windows-Kernel-Power"),
            make_pair("SA_VM_EXCEPTION_SHUTDOWN", vector<pair<string, string>>{
            make_pair("TimeGenerated", "/Event/System/TimeCreated/@SystemTime"),
            make_pair("BugcheckCode", "/Event/EventData/Data[@Name='BugcheckCode']"),
            make_pair("BugcheckParameter1", "/Event/EventData/Data[@Name='BugcheckParameter1']"),
            make_pair("BugcheckParameter2", "/Event/EventData/Data[@Name='BugcheckParameter2']"),
            make_pair("BugcheckParameter3", "/Event/EventData/Data[@Name='BugcheckParameter3']"),
            make_pair("BugcheckParameter4", "/Event/EventData/Data[@Name='BugcheckParameter4']"),
            make_pair("SleepInProgress", "/Event/EventData/Data[@Name='SleepInProgress']"),
            make_pair("PowerButtonTimestamp", "/Event/EventData/Data[@Name='PowerButtonTimestamp']"), }) },
        { make_pair(EVENTID_APPLICATION_HANG, "Application Hang"),
            make_pair("SA_VM_APPLICATION_HANG", vector<pair<string, string>>{
            make_pair("ProcessName", "/Event/EventData/Data[@Name='AppName']"),
            make_pair("ProcessVersion", "/Event/EventData/Data[@Name='AppVersion']"), }) },
        { make_pair(EVENTID_APPLICATION_ERROR, "Application Error"),
            make_pair("SA_VM_APPLICATION_ERROR", vector<pair<string, string>>{
            make_pair("ProcessName", "/Event/EventData/Data[@Name='AppName']"),
            make_pair("ProcessVersion", "/Event/EventData/Data[@Name='AppVersion']"),
            make_pair("ModuleName", "/Event/EventData/Data[@Name='ModuleName']"),
            make_pair("ModuleVersion", "/Event/EventData/Data[@Name='ModuleVersion']"),
        }) },
        { make_pair(EVENTID_WINDOWS_ERROR_REPORTING, "Windows Error Reporting"),
            make_pair("SA_VM_WINDOWS_ERROR_REPORTING", vector<pair<string, string>>{
            make_pair("Description1", "/Event/EventData/Data[@Name='Bucket']"),
            make_pair("Description2", "/Event/EventData/Data[@Name='BucketType']"),
            make_pair("Description3", "/Event/EventData/Data[@Name='EventName']"),
            make_pair("Description4", "/Event/EventData/Data[@Name='Response']"),
            make_pair("Description5", "/Event/EventData/Data[@Name='CabId']"),
            make_pair("Problem1", "/Event/EventData/Data[@Name='P1']"),
            make_pair("Problem2", "/Event/EventData/Data[@Name='P2']"),
            make_pair("Problem3", "/Event/EventData/Data[@Name='P3']"),
            make_pair("Problem4", "/Event/EventData/Data[@Name='P4']"),
            make_pair("Problem5", "/Event/EventData/Data[@Name='P5']"),
            make_pair("Problem6", "/Event/EventData/Data[@Name='P6']"),
            make_pair("Problem7", "/Event/EventData/Data[@Name='P7']"),
            make_pair("Problem8", "/Event/EventData/Data[@Name='P8']"),
            make_pair("Problem9", "/Event/EventData/Data[@Name='P9']"),
            make_pair("Problem10", "/Event/EventData/Data[@Name='P10']"), }) },
        { make_pair(EVENTID_WINDOWS_ERROR_REPORTING, "Microsoft-Windows-WER-SystemErrorReporting"),
            make_pair("SA_VM_MINIDUMP_UPLOAD_EVENT", vector<pair<string, string>>{
            make_pair("param1", "/Event/EventData/Data[@Name='param1']"), }) },
        { make_pair(EVENTID_MEM_NOTENOUGH, "Microsoft-Windows-Resource-Exhaustion-Detector"),
            make_pair("SA_VM_VIRTUAL_MEM_NOTENOUGH", vector<pair<string, string>>{
            make_pair("Process_1", "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_1/Name"),
            make_pair("Process_1_CommitCharge",
                "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_1/CommitCharge"),
            make_pair("Process_2", "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_2/Name"),
            make_pair("Process_2_CommitCharge",
                "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_2/CommitCharge"),
            make_pair("Process_3", "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_3/Name"),
            make_pair("Process_3_CommitCharge",
                "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_3/CommitCharge"),
            make_pair("Process_4", "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_4/Name"),
            make_pair("Process_4_CommitCharge",
                "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_4/CommitCharge"),
            make_pair("Process_5", "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_5/Name"),
            make_pair("Process_5_CommitCharge",
                "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_5/CommitCharge"),
            make_pair("Process_6", "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_6/Name"),
            make_pair("Process_6_CommitCharge",
                "/Event/UserData/MemoryExhaustionInfo/ProcessInfo/Process_6/CommitCharge"),
        }) },
    };

    static const DWORD RENDER_EVENT_ARRAY_SIZE = 10;
    static const DWORD N_MAX_RENDER_BUFF = 102400; // 100k，系统日志缓冲区，足够获取event数据
    static const int MICROSECONDS_WIDTH = 6;
    static const int MICROSECONDS_OF_SECOND = 1000000;
    static const int FIRST_BOOT_CHECK_MINUTES = 5;
};
}

#define LOG_EVENT_HANDLER SingletonNew<DFX::LogEventHandler>::GetInstance()

#endif